package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.NewsAutoScanConstants;
import com.heima.common.exception.CustException;
import com.heima.common.exception.CustomException;
import com.heima.model.common.constants.WemediaConstants;
import com.heima.model.common.constants.WmNewsMessageConstants;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.NewsAuthDto;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.model.wemedia.vos.WmNewsVo;
import com.heima.utils.threadlocal.WmThreadLocalUtils;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    WmMaterialMapper wmMaterialMapper;

    @Autowired
    KafkaTemplate kafkaTemplate;

    @Autowired
    WmNewsMapper wmNewsMapper;

    @Autowired
    WmUserMapper wmUserMapper;

    @Value("${file.oss.web-site}")
    String webSite;


    /**
     * 自媒体文章人工审核
     *
     * @param status 2  审核失败  4 审核成功
     * @param dto
     * @return
     */
    @Override
    public ResponseResult updateStatus(Short status, NewsAuthDto dto) {
        //参数校验
        if (dto == null || dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //查询
        WmNews wmNews = getById(dto.getId());
        if (wmNews ==null ||wmNews.getStatus().intValue() == 9
                || wmNews.getStatus().intValue() == 8 ){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST,"文章已审核");
        }

        //修改状态
        wmNews.setStatus(status);
        if (StringUtils.isNotBlank(dto.getMsg())){
            wmNews.setReason(dto.getMsg());
        }

        updateById(wmNews);


        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 根据id查询文章详情
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult findWmNewsVo(Integer id) {
        //参数校验
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //查询wmNews
        WmNews wmNews = getById(id);

        if (wmNews == null || wmNews.getUserId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        //查询wmUser 把wmUser的名字设置给wmNewsVo
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());

        WmNewsVo wmNewsVo = new WmNewsVo();
        BeanUtils.copyProperties(wmNews, wmNewsVo);


        if (wmUser != null) {
            wmNewsVo.setAuthorName(wmUser.getName());
        }

        ResponseResult result = ResponseResult.okResult(wmNewsVo);

        //处理图片前缀
        result.setHost(webSite);


        return result;
    }

    /**
     * 查询文章列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findList(NewsAuthDto dto) {
        //参数校验
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //检查分页
        dto.checkParam();


        //处理页码
        Integer page = dto.getPage();
        int npage = (page - 1) * dto.getSize();
        dto.setPage(npage);

        //处理标题模糊搜索
        if (StringUtils.isNotBlank(dto.getTitle())) {
            dto.setTitle("%" + dto.getTitle() + "%");
        }

        //查询
        List<WmNewsVo> listAndPage = wmNewsMapper.findListAndPage(dto);

        long count = wmNewsMapper.findListCount(dto);
        //封装参数，返回结果
        ResponseResult result = new PageResponseResult(npage, dto.getSize(), count, listAndPage);

        //处理图片前缀
        result.setHost(webSite);

        return result;
    }

    /**
     * 查询需要发布的文章id列表
     *
     * @return
     */
    @Override
    public List<Integer> findRelease() {
        //根据id进行查询，得到wmNews集合
        List<WmNews> list = list(Wrappers.<WmNews>lambdaQuery()
                .le(WmNews::getPublishTime, new Date())
                .in(WmNews::getStatus, 4, 8)
                .select(WmNews::getId)
        );

        //使用流式编程，得到id集合
        List<Integer> idList = list.stream().map(WmNews::getId).collect(Collectors.toList());


        return idList;
    }

    /**
     * 上下架
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //1、参数校验
        if (dto == null || dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //2、查询文章
        WmNews wmNews = getById(dto.getId());
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }


        //3、判断文章是否发布
        if (!wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "当前文章不是发布状态，不能上下架");
        }

        //4、修改文章状态
        if (wmNews.getEnable() != null) {
            wmNews.setEnable(dto.getEnable());
            updateById(wmNews);
        }


        if (wmNews.getArticleId()!=null){
            Map<String, Object> map = new HashMap();
            map.put("enable",wmNews.getEnable());
            map.put("articleId",wmNews.getArticleId());

            kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC,JSON.toJSONString(map));
        }


        //5、返回结果
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 删除文章
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult delNews(Integer id) {
        //1、参数校验
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //2、获取数据
        WmNews wmNews = getById(id);
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        //3、判断当前文章状态
        if (wmNews.getStatus().equals(WmNews.Status.PUBLISHED) &&
                wmNews.getEnable().equals(WemediaConstants.WM_NEWS_UPENABLE)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        //4、去除素材与文章之间的关系
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                .eq(WmNewsMaterial::getNewsId, wmNews.getId()));

        //5、删除文章
        removeById(wmNews.getId());
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 根据文章id查询文章
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult findWmNewsById(Integer id) {
        //1、参数校验
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //2、执行查询
        WmNews wmNews = getById(id);
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        //3、返回结果
        ResponseResult result = ResponseResult.okResult(wmNews);
        result.setHost(webSite);
        return result;
    }

    /**
     * 自媒体文章发布
     *
     * @param wmNewsDto
     * @param isSubmit  是否为提交 1 为提交 0为草稿
     * @return
     */
    @Override
    @Transactional
    public ResponseResult saveNews(WmNewsDto wmNewsDto, Short isSubmit) {
        //1、参数校验
        if (wmNewsDto == null || StringUtils.isBlank(wmNewsDto.getContent())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }


        //2、保存或修改文章
        WmNews wmNews = new WmNews();
        //把wmNewsDto中的数据拷贝到wmNews中
        BeanUtils.copyProperties(wmNewsDto, wmNews);

        //当文章布局为自动的时候，设置type为null
        if (wmNewsDto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
            wmNews.setType(null);
        }

        //把images集合转换成字符串
        String images = imageListToStr(wmNewsDto.getImages(), webSite);
        wmNews.setImages(images);
        saveWmNews(wmNews, isSubmit);
        //3、关联文章和素材的关系（isSubmit=1 提交时关联）
        List<Map> contents = JSON.parseArray(wmNewsDto.getContent(), Map.class);
        //解析文章内容中的图片列表
        List<String> materials = parseContentImages(contents);

        //3.1 关联文章 内容  和素材的关系
        if (isSubmit == WmNews.Status.SUBMIT.getCode() && materials.size() > 0) {
            saveRelativeInfoForContent(materials, wmNews.getId());
        }


        //3.2 关联文章 封面  和素材的关系
        if (isSubmit == WmNews.Status.SUBMIT.getCode()) {
            saveRelativeInfoForCover(wmNewsDto, materials, wmNews);
        }

        //发消息给admin审核文章
        Map map = new HashMap();
        map.put("wmNewsId", wmNews.getId());
        kafkaTemplate.send(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC, JSON.toJSONString(map));

        //4、返回结果

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 保存文章 封面 和素材关系
     *
     * @param wmNewsDto # images 图片封面带前缀
     * @param materials 文章内容中的图片列表#无图片前缀
     * @param wmNews    文章对象
     */
    private void saveRelativeInfoForCover(WmNewsDto wmNewsDto, List<String> materials, WmNews wmNews) {
        //获取图片封面
        List<String> images = wmNewsDto.getImages();

        //判断type是否是自动
        if (wmNewsDto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {

            int size = materials.size();
            if (size > 0 && size <= 2) {//单图
                images = materials.stream().limit(1).collect(Collectors.toList());
                wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
            } else if (size >= 3) {//三图
                images = materials.stream().limit(3).collect(Collectors.toList());
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
            } else {//无图
                wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
            }

            if (images != null) {
                wmNews.setImages(imageListToStr(images, webSite));
            }

            updateById(wmNews);
        }


        if (images != null && images.size() > 0) {
            saveRelativeInfoForImage(images, wmNews.getId());
        }

    }


    /**
     * 保存文章封面和图片关系
     *
     * @param images
     * @param id
     */
    private void saveRelativeInfoForImage(List<String> images, Integer id) {

        images = images.stream().map(x ->
                x.replace(webSite, "")
                        .replace(" ", "")
        ).collect(Collectors.toList());


        saveRelativeInfo(images, id, WemediaConstants.WM_IMAGE_REFERENCE);
    }


    /**
     * 关联文章 内容  和素材的关系
     *
     * @param materials 图片列表
     * @param id        wmNewsId
     */
    private void saveRelativeInfoForContent(List<String> materials, Integer id) {
        saveRelativeInfo(materials, id, WemediaConstants.WM_CONTENT_REFERENCE);
    }


    /**
     * 执行保存文章素材关系
     *
     * @param materials 图片列表
     * @param wmNewsId  wmNewsId
     * @param type      引用类型  0：内容  1：封面
     */
    private void saveRelativeInfo(List<String> materials, Integer wmNewsId, Short type) {
        //查询文章中对应的素材id
        List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery()
                .in(WmMaterial::getUrl, materials)
                .eq(WmMaterial::getUserId, WmThreadLocalUtils.getUser().getId())
        );

        //校验素材列表
        if (wmMaterials == null || wmMaterials.size() == 0) {
            throw new CustomException(AppHttpCodeEnum.FILE_MATERIAL_ISNULL_ERROR);
        }
        List<Integer> materialIds = new ArrayList<>();

        Map<String, Integer> matreialMap = wmMaterials.stream().
                collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));

        for (String url : materials) {
            Integer id = matreialMap.get(url);
            if (id == null) {
                CustException.cust(AppHttpCodeEnum.FILE_MATERIAL_ISNULL_ERROR);
            }
            materialIds.add(id);
        }

        //批量查询
        wmNewsMaterialMapper.saveRelations(materialIds, wmNewsId, type);
    }


    /**
     * 解析文章内容中的图片列表
     *
     * @param contents 文章内容
     * @return
     */
    private List<String> parseContentImages(List<Map> contents) {
        List<String> materials = new ArrayList<>();

        for (Map<String, String> content : contents) {
            if (content.get("type").equals(WemediaConstants.WM_NEWS_TYPE_IMAGE)) {
                String imageUrl = content.get("value")
                        .replace(webSite, "")
                        .replace(" ", "");
                materials.add(imageUrl);
            }

        }

        return materials;
    }

    /**
     * 保存或者修改文章
     *
     * @param wmNews   文章对象
     * @param isSubmit 0：存入草稿  1：提交审核
     */
    private void saveWmNews(WmNews wmNews, Short isSubmit) {
        wmNews.setCreatedTime(new Date());
        wmNews.setUserId(WmThreadLocalUtils.getUser().getId());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable(WemediaConstants.WM_NEWS_UPENABLE);  //设置保存就默认上架

        if (wmNews.getId() == null) {//如果id为空则创建文章
            save(wmNews);
        } else {//如果不为空则修改文章
            //先删后加
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                    .eq(WmNewsMaterial::getNewsId, wmNews.getId())
            );
            updateById(wmNews);

        }
    }

    /**
     * 把images集合转化成字符串 并把图片前缀去掉
     *
     * @param images  图片列表
     * @param webSite 图片前缀
     * @return
     */
    private String imageListToStr(List<String> images, String webSite) {

        return images.toString()
                .replace("[", "")
                .replace(" ", "")
                .replace("]", "")
                .replace(webSite, "");
    }

    /**
     * 查询所有自媒体文章
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findAll(WmNewsPageReqDto dto) {
        //1、参数校验
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //检查分页参数
        dto.checkParam();

        //2、封装条件

        IPage<WmNews> paramPage = new Page<>(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<WmNews> query = new LambdaQueryWrapper<>();

        //关键字模糊查询
        if (StringUtils.isNotBlank(dto.getKeyword())) {
            query.like(WmNews::getTitle, dto.getKeyword());
        }

        //审核状态查询
        if (dto.getStatus() != null) {
            query.eq(WmNews::getStatus, dto.getStatus());
        }

        //频道id查询
        if (dto.getChannelId() != null) {
            query.eq(WmNews::getChannelId, dto.getChannelId());
        }

        //发布日期查询
        if (dto.getBeginPubDate() != null && dto.getEndPubDate() != null) {
            query.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());
        }


        //获取自媒体人id
        WmUser user = WmThreadLocalUtils.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //根据uesrId查询
        query.eq(WmNews::getUserId, user.getId());

        //根据时间倒序查询
        query.orderByDesc(WmNews::getCreatedTime);


        //3、执行查询
        IPage<WmNews> pageResult = page(paramPage, query);


        //4、返回结果
        PageResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), pageResult.getTotal(), pageResult.getRecords());

        //处理图片
        result.setHost(webSite);

        return result;
    }
}
